package yyn

import (
	"fmt"
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/data/validation"
	"fyne.io/fyne/v2/widget"
	"strconv"
)

type cameraBind struct {
	CaNum    binding.Int //相机数量
	CodeRate binding.Int //码流
	//ClarityH   binding.Int //分辨率-水平
	//ClarityV   binding.Int //分辨率-垂直
	//Frame      binding.Int //帧率
	ChannelNum binding.Int    //码流路数
	Result1    binding.Int    //结果 Byte
	Result2    binding.Int    //结果 KB
	Result3    binding.String //结果 MB
	Result4    binding.String //结果 Mbps
}

type pointDataBind struct {
	LadarNum binding.Int    //雷达数
	PackNum  binding.Int    //每秒包数
	ByteNum  binding.Int    //每包字节数
	Result1  binding.Int    //结果 Byte
	Result2  binding.Int    //结果 KB
	Result3  binding.String //结果 MB
	Result4  binding.String //结果 Mbps
}

//主码流
var mainBindDto = &cameraBind{
	CaNum:    binding.NewInt(),
	CodeRate: binding.NewInt(),
	//ClarityH:   binding.NewInt(),
	//ClarityV:   binding.NewInt(),
	//Frame:      binding.NewInt(),
	ChannelNum: binding.NewInt(),
	Result1:    binding.NewInt(),
	Result2:    binding.NewInt(),
	Result3:    binding.NewString(),
	Result4:    binding.NewString(),
}

//辅码流
var subBindDto = &cameraBind{
	CaNum:    binding.NewInt(),
	CodeRate: binding.NewInt(),
	//ClarityH:   binding.NewInt(),
	//ClarityV:   binding.NewInt(),
	//Frame:      binding.NewInt(),
	ChannelNum: binding.NewInt(),
	Result1:    binding.NewInt(),
	Result2:    binding.NewInt(),
	Result3:    binding.NewString(),
	Result4:    binding.NewString(),
}

//点云
var pointDataBindDto = &pointDataBind{
	LadarNum: binding.NewInt(),
	PackNum:  binding.NewInt(),
	ByteNum:  binding.NewInt(),
	Result1:  binding.NewInt(),
	Result2:  binding.NewInt(),
	Result3:  binding.NewString(),
	Result4:  binding.NewString(),
}

//总记
var totalLabDto = binding.NewString()
var totalLabDtoData = "总结果: 0"

func Flow() fyne.CanvasObject {
	//标题
	title := widget.NewLabel("流量估算")
	title.Alignment = fyne.TextAlignCenter

	//主码流
	mainTitle := widget.NewLabel("相机-主码流量")
	mainTitle.Alignment = fyne.TextAlignCenter

	//main-form
	_, mainCaNumItem := rowInt2("相机数量", mainBindDto.CaNum)
	_, mainCodeRateItem := rowInt2("码率(kbs)", mainBindDto.CodeRate)
	//_, mainClarityHItem := rowInt2("分辨率-水平像素点", mainBindDto.ClarityH)
	//_, mainClarityVItem := rowInt2("分辨率-垂直像素点", mainBindDto.ClarityV)
	//_, mainFrameItem := rowInt2("帧率", mainBindDto.Frame)
	_, mainChannelNumItem := rowInt2("码流路数", mainBindDto.ChannelNum)
	_, mainResultNumItem1 := rowInt2("实际-Byte/s", mainBindDto.Result1)
	_, mainResultNumItem2 := rowInt2("实际-KB/s", mainBindDto.Result2)
	_, mainResultNumItem3 := rowString("实际-MB/s", mainBindDto.Result3)
	_, mainResultNumItem4 := rowString("网络带宽-Mbp/s", mainBindDto.Result4)
	mainForm := &widget.Form{
		Items: []*widget.FormItem{
			mainCaNumItem,
			mainCodeRateItem,
			//mainClarityHItem,
			//mainClarityVItem,
			//mainFrameItem,
			mainChannelNumItem,
			mainResultNumItem1,
			mainResultNumItem2,
			mainResultNumItem3,
			mainResultNumItem4,
		},
		OnCancel: func() {
			initMainData()
			calculateTotal()

		},
		CancelText: "重置",
		SubmitText: "主码流计算",
		OnSubmit: func() {
			calculateMain()
			calculateTotal()
		},
	}

	//辅码流
	subTitle := widget.NewLabel("相机-辅码流量")
	subTitle.Alignment = fyne.TextAlignCenter

	_, subCaNumItem := rowInt2("相机数量", subBindDto.CaNum)
	_, subCodeRateItem := rowInt2("码率(kbs)", subBindDto.CodeRate)
	//_, subClarityHItem := rowInt2("分辨率-水平像素点", subBindDto.ClarityH)
	//_, subClarityVItem := rowInt2("分辨率-垂直像素点", subBindDto.ClarityV)
	//_, subFrameItem := rowInt2("帧率", subBindDto.Frame)
	_, subChannelNumItem := rowInt2("码流路数", subBindDto.ChannelNum)
	_, subResultNumItem1 := rowInt2("实际-Byte/s", subBindDto.Result1)
	_, subResultNumItem2 := rowInt2("结果-KB/s", subBindDto.Result2)
	_, subResultNumItem3 := rowString("结果-MB/s", subBindDto.Result3)
	_, subResultNumItem4 := rowString("网络带宽-Mbp/s", subBindDto.Result4)
	subForm := &widget.Form{
		Items: []*widget.FormItem{
			subCaNumItem,
			subCodeRateItem,
			//subClarityHItem,
			//subClarityVItem,
			//subFrameItem,
			subChannelNumItem,
			subResultNumItem1,
			subResultNumItem2,
			subResultNumItem3,
			subResultNumItem4,
		},
		OnCancel: func() {
			initSubData()
			calculateTotal()
		},
		CancelText: "重置",
		SubmitText: "辅码流计算",
		OnSubmit: func() {
			calculateSub()
			calculateTotal()
		},
	}

	//点云
	cTitle := widget.NewLabel("点云流量")
	cTitle.Alignment = fyne.TextAlignCenter

	_, pointLadarItem := rowInt2("雷达数", pointDataBindDto.LadarNum)
	_, pointPackItem := rowInt2("每秒包数", pointDataBindDto.PackNum)
	_, pointByteItem := rowInt2("每包字节", pointDataBindDto.ByteNum)
	_, pointResultNumItem1 := rowInt2("实际-Byte/s", pointDataBindDto.Result1)
	_, pointResultNumItem2 := rowInt2("实际-KB/s", pointDataBindDto.Result2)
	_, pointResultNumItem3 := rowString("实际-MB/s", pointDataBindDto.Result3)
	_, pointResultNumItem4 := rowString("网络带宽-Mbp/s", pointDataBindDto.Result4)

	pointForm := &widget.Form{
		Items: []*widget.FormItem{
			pointLadarItem,
			pointPackItem,
			pointByteItem,
			pointResultNumItem1,
			pointResultNumItem2,
			pointResultNumItem3,
			pointResultNumItem4,
		},
		OnCancel: func() {
			initPointData()
			calculateTotal()
		},
		CancelText: "重置",
		SubmitText: "点云计算",
		OnSubmit: func() {
			calculatePoint()
			calculateTotal()
		},
	}

	separator1 := widget.NewSeparator()
	separator2 := widget.NewSeparator()
	separator3 := widget.NewSeparator()
	box := container.NewGridWithColumns(3,
		container.NewBorder(nil, nil, nil, widget.NewSeparator(), container.NewVBox(mainTitle, separator1, mainForm)),
		container.NewBorder(nil, nil, nil, widget.NewSeparator(), container.NewVBox(subTitle, separator2, subForm)),
		container.NewVBox(cTitle, separator3, pointForm),
	)

	bottom := widget.NewLabelWithData(totalLabDto)
	bottom.Alignment = fyne.TextAlignCenter

	initData()
	return container.NewBorder(
		container.NewVBox(title, widget.NewSeparator()),
		container.NewVBox(widget.NewSeparator(), bottom),
		nil,
		nil,
		box)

}
func initData() {
	//点云
	initPointData()
	//主码
	initMainData()
	//辅码
	initSubData()
	//结果
	totalLabDto.Set(totalLabDtoData)
}

func initSubData() {
	subBindDto.CaNum.Set(1)
	subBindDto.CodeRate.Set(2048)
	//subBindDto.ClarityH.Set(704)
	//subBindDto.ClarityV.Set(576)
	//subBindDto.Frame.Set(10)
	subBindDto.ChannelNum.Set(1)
	subBindDto.Result1.Set(0)
	subBindDto.Result2.Set(0)
	subBindDto.Result3.Set("待计算")
	subBindDto.Result4.Set("待计算")
}

func initMainData() {
	mainBindDto.CaNum.Set(1)
	mainBindDto.CodeRate.Set(4096)
	//mainBindDto.ClarityH.Set(1920)
	//mainBindDto.ClarityV.Set(1080)
	//mainBindDto.Frame.Set(10)
	mainBindDto.ChannelNum.Set(1)
	mainBindDto.Result1.Set(0)
	mainBindDto.Result2.Set(0)
	mainBindDto.Result3.Set("待计算")
	mainBindDto.Result4.Set("待计算")
}

func initPointData() {
	pointDataBindDto.LadarNum.Set(1)
	pointDataBindDto.PackNum.Set(1800)
	pointDataBindDto.ByteNum.Set(1350)
	pointDataBindDto.Result1.Set(0)
	pointDataBindDto.Result2.Set(0)
	pointDataBindDto.Result3.Set("待计算")
	pointDataBindDto.Result4.Set("待计算")
}

func calculateTotal() {

	mainBit, _ := mainBindDto.Result1.Get()
	subBit, _ := subBindDto.Result1.Get()
	pointBit, _ := pointDataBindDto.Result1.Get()

	totalBit := mainBit + subBit + pointBit
	totalKb := totalBit / 1024
	totalMb, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(totalKb)/float64(1024)), 64)

	msg := strconv.Itoa(totalBit) + " Byte/s  " +
		strconv.Itoa(totalKb) + " KB/s  " +
		fmt.Sprintf("%.2f", totalMb) + " MB/s  网络带宽:" +
		fmt.Sprintf("%.2f", totalMb*float64(8)) + " Mbp/s  "
	totalLabDto.Set("实际: " + msg)

}

func calculateMain() {
	codeRate, _ := mainBindDto.CodeRate.Get()
	//hRate, _ := mainBindDto.ClarityH.Get()
	//vRate, _ := mainBindDto.ClarityV.Get()
	//frame, _ := mainBindDto.Frame.Get()
	caNum, _ := mainBindDto.CaNum.Get()
	channelNum, _ := mainBindDto.ChannelNum.Get()
	//single := calculateCamera(codeRate, hRate, vRate, frame)
	codeRate = codeRate / 8
	single := codeRate * 1024
	bitResult := single * caNum * channelNum
	kbResult := bitResult / 1024
	mbtResult := float64(kbResult) / float64(1024)
	netResult := mbtResult * float64(8)
	mainBindDto.Result1.Set(bitResult)
	mainBindDto.Result2.Set(kbResult)
	mainBindDto.Result3.Set(fmt.Sprintf("%.2f", mbtResult))
	mainBindDto.Result4.Set(fmt.Sprintf("%.2f", netResult))
}

func calculateSub() {
	codeRate, _ := subBindDto.CodeRate.Get()
	//hRate, _ := subBindDto.ClarityH.Get()
	//vRate, _ := subBindDto.ClarityV.Get()
	//frame, _ := subBindDto.Frame.Get()
	caNum, _ := subBindDto.CaNum.Get()
	channelNum, _ := subBindDto.ChannelNum.Get()
	//single := calculateCamera(codeRate, hRate, vRate, frame)
	codeRate = codeRate / 8
	single := codeRate * 1024
	bitResult := single * caNum * channelNum
	kbResult := bitResult / 1024
	mbtResult := float64(kbResult) / float64(1024)
	netResult := mbtResult * float64(8)
	subBindDto.Result1.Set(bitResult)
	subBindDto.Result2.Set(kbResult)
	subBindDto.Result3.Set(fmt.Sprintf("%.2f", mbtResult))
	subBindDto.Result4.Set(fmt.Sprintf("%.2f", netResult))
}

func calculatePoint() {
	num, _ := pointDataBindDto.LadarNum.Get()
	pack, _ := pointDataBindDto.PackNum.Get()
	bit, _ := pointDataBindDto.ByteNum.Get()

	bitResult := bit * pack * num
	kbResult := bitResult / 1024
	mbtResult := fmt.Sprintf("%.2f", float64(kbResult)/float64(1024))
	netResult := fmt.Sprintf("%.2f", float64(kbResult)*8/float64(1024))
	pointDataBindDto.Result1.Set(bitResult)
	pointDataBindDto.Result2.Set(kbResult)
	pointDataBindDto.Result3.Set(mbtResult)
	pointDataBindDto.Result4.Set(netResult)

}

/*
首先，计算每帧的数据量bytes_per_frame，其表示视频数据和音频数据的总和。
然后，计算每秒的总数据量total_bytes_per_second，其表示整个视频流每秒的数据量，单位为字节。其中，码率bitrate表示每秒传输的比特数，需要将其除以8才能得到每秒传输的字节数。
接着，计算每帧视频数据的大小video_bytes_per_frame，其为每帧数据量的一个固定比例。
由于视频数据和音频数据的比例是固定的，因此可以将每帧音频数据的大小计算为audio_bytes_per_frame = bytes_per_frame - video_bytes_per_frame。
然后，计算每秒的视频数据量total_video_bytes_per_second，其为每秒的总数据量total_bytes_per_second减去音频数据的总量。由于本算法中假设音频数据量较小，可以忽略不计，因此可将total_video_bytes_per_second近似地看作整个视频流每秒的流量大小。
最后，将每秒的流量大小total_video_bytes_per_second加上每一帧的音频数据量audio_bytes_per_frame和每一帧的数据量total_bytes_per_frame即可得到每秒的流量大小，即stream_size = total_bytes_per_frame + audio_bytes_per_frame。
由于本算法中假设视频数据和音频数据的比例是固定的，因此可以将audio_bytes_per_frame近似地看作total_bytes_per_frame，从而得到stream_size = 2 * total_bytes_per_frame，即每秒的流量大小。
*/
/**
参数
	codeRate:码流
	hRate:分辨率 横向
	vRate：分辨率 竖向
	frame: 帧率
返回值
	每秒流量 bit/s
*/
func calculateCamera(codeRate int, hRate int, vRate int, frame int) (bit int) {
	// 每个像素的位深度为24位，即每个像素使用3个字节
	bytesPerPixel := 3
	// 计算每帧的数据量
	bytesPerFrame := hRate * vRate * bytesPerPixel
	// 计算总数据量
	totalBytesPerSecond := (codeRate / 8) * frame
	totalBytesPerFrame := totalBytesPerSecond / frame
	// 计算每秒流量大小
	streamSize := totalBytesPerFrame + bytesPerFrame
	return streamSize
}

func rowInt2(lableName string, bind binding.Int) (*widget.Entry, *widget.FormItem) {
	str := binding.IntToString(bind)
	mainCaNumEn := widget.NewEntryWithData(str)
	mainCaNumItem := widget.NewFormItem(lableName, mainCaNumEn)
	mainCaNumEn.Validator = validation.NewRegexp(`^[0-9]+$`, "请输入整数")
	return mainCaNumEn, mainCaNumItem
}
func rowString(lableName string, bind binding.String) (*widget.Entry, *widget.FormItem) {
	mainCaNumEn := widget.NewEntryWithData(bind)
	mainCaNumItem := widget.NewFormItem(lableName, mainCaNumEn)
	return mainCaNumEn, mainCaNumItem
}
